package com.wenx.v3system.modular.platform.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wenx.v3dynamicdatasourcestarter.config.DynamicDataSourceConfig;
import com.wenx.v3system.modular.platform.domain.dto.PlatformRoleDto;
import com.wenx.v3system.modular.platform.domain.maps.PlatformRoleMap;
import com.wenx.v3system.modular.platform.domain.po.PlatformRole;
import com.wenx.v3system.modular.platform.domain.query.PlatformRoleQuery;
import com.wenx.v3secure.enums.PlatformRoleType;
import com.wenx.v3system.modular.platform.mapper.PlatformRoleMapper;
import com.wenx.v3system.modular.platform.service.PlatformRoleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 平台角色服务实现类
 * 参考rbac模块风格重构
 * 使用v3-platform数据源
 * 
 * @author wenx
 */
@Slf4j
@Service
@RequiredArgsConstructor
@DS(DynamicDataSourceConfig.PLATFORM_DATASOURCE)
public class PlatformRoleServiceImpl extends ServiceImpl<PlatformRoleMapper, PlatformRole> implements PlatformRoleService {

    @Override
    public IPage<?> page(PlatformRoleQuery query) {
        LambdaQueryWrapper<PlatformRole> wrapper = new LambdaQueryWrapper<PlatformRole>()
                .like(StringUtils.hasText(query.getName()), PlatformRole::getName, query.getName())
                .like(StringUtils.hasText(query.getCode()), PlatformRole::getCode, query.getCode())
                .eq(query.getIsBuiltin() != null, PlatformRole::getIsBuiltin, query.getIsBuiltin())
                .eq(query.getStatus() != null, PlatformRole::getStatus, query.getStatus())
                .orderByDesc(PlatformRole::getCreateTime);
        
        IPage<PlatformRole> result = super.page(new Page<>(query.getCurrent(), query.getSize()), wrapper);
        return result.convert(this::convertToDto);
    }

    @Override
    public Object get(Serializable id) {
        PlatformRole role = super.getById(id);
        return role != null ? convertToDto(role) : null;
    }

    @Override
    public void add(PlatformRoleDto dto) {
        // 检查编码是否存在
        if (checkCodeExists(dto.getCode(), null)) {
            throw new RuntimeException("角色编码已存在");
        }

        PlatformRole role = PlatformRoleMap.INSTANCE.toPo(dto);
        
        // 自定义角色不能设置为内置
        role.setIsBuiltin(false);
        role.setStatus(1); // 默认启用
        
        super.save(role);
        log.info("平台角色创建成功: roleId={}, code={}", role.getId(), role.getCode());
    }

    @Override
    public void delete(Serializable id) {
        PlatformRole role = super.getById(id);
        if (role == null) {
            throw new RuntimeException("角色不存在");
        }
        
        // 内置角色不能删除
        if (Boolean.TRUE.equals(role.getIsBuiltin())) {
            throw new RuntimeException("内置角色不能删除");
        }
        
        super.removeById(id);
        log.info("平台角色删除成功: roleId={}", id);
    }

    @Override
    public void update(PlatformRoleDto dto) {
        if (dto.getId() == null) {
            throw new RuntimeException("角色ID不能为空");
        }
        
        PlatformRole existingRole = super.getById(dto.getId());
        if (ObjectUtil.isEmpty(existingRole)) {
            throw new RuntimeException("角色不存在");
        }
        
        // 内置角色只能修改部分字段
        if (Boolean.TRUE.equals(existingRole.getIsBuiltin())) {
            // 内置角色只能修改描述和状态
            existingRole.setDescription(dto.getDescription());
            existingRole.setStatus(dto.getStatus());
        } else {
            // 检查编码是否重复
            if (checkCodeExists(dto.getCode(), dto.getId())) {
                throw new RuntimeException("角色编码已存在");
            }
            
            BeanUtils.copyProperties(dto, existingRole);
            existingRole.setIsBuiltin(false); // 确保自定义角色标记正确
        }
        
        super.updateById(existingRole);
        log.info("平台角色更新成功: roleId={}", dto.getId());
    }

    @Override
    public List<PlatformRoleDto> getAllRoles() {
        // 直接从数据库获取所有角色
        List<PlatformRole> allRoles = this.list();
        return allRoles.stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

    @Override
    public List<PlatformRoleDto> getBuiltinRoles() {
        return Arrays.stream(PlatformRoleType.values())
                .map(this::convertBuiltinRoleToDto)
                .collect(Collectors.toList());
    }

    @Override
    public List<PlatformRoleDto> getCustomRoles() {
        List<PlatformRole> customRoles = this.list(
            new LambdaQueryWrapper<PlatformRole>()
                .eq(PlatformRole::getIsBuiltin, false)
                .eq(PlatformRole::getStatus, 1)
                .orderByAsc(PlatformRole::getSort)
        );
        
        return customRoles.stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

    @Override
    public PlatformRoleDto getRoleByCode(String code) {
        // 先检查是否为内置角色
        PlatformRoleType builtinRole = PlatformRoleType.fromCode(code);
        if (builtinRole != null) {
            return convertBuiltinRoleToDto(builtinRole);
        }
        
        // 查询自定义角色
        PlatformRole role = this.getOne(
            new LambdaQueryWrapper<PlatformRole>()
                .eq(PlatformRole::getCode, code)
        );
        
        return role != null ? convertToDto(role) : null;
    }

    @Override
    public boolean checkCodeExists(String code, Long excludeId) {
        // 检查是否为内置角色代码
        if (PlatformRoleType.fromCode(code) != null) {
            return true;
        }
        
        // 检查自定义角色
        LambdaQueryWrapper<PlatformRole> wrapper = new LambdaQueryWrapper<PlatformRole>()
                .eq(PlatformRole::getCode, code);
        
        if (excludeId != null) {
            wrapper.ne(PlatformRole::getId, excludeId);
        }
        
        return this.count(wrapper) > 0;
    }


    @Override
    public List<String> getRoleCodesByIds(List<String> roleIds) {
        if (roleIds == null || roleIds.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 将字符串ID转换为Long类型，过滤无效ID
        List<Long> longIds = roleIds.stream()
                .map(this::parseRoleId)
                .filter(id -> id != null)
                .collect(Collectors.toList());
        
        if (longIds.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 批量查询角色并返回角色代码
        return super.listByIds(longIds).stream()
                .map(PlatformRole::getCode)
                .collect(Collectors.toList());
    }
    
    /**
     * 解析角色ID，处理异常情况
     * @param id 角色ID字符串
     * @return 解析后的Long类型ID，解析失败返回null
     */
    private Long parseRoleId(String id) {
        try {
            return Long.parseLong(id);
        } catch (NumberFormatException e) {
            log.warn("无效的角色ID: {}", id);
            return null;
        }
    }

    /**
     * 转换内置角色为DTO
     */
    private PlatformRoleDto convertBuiltinRoleToDto(PlatformRoleType roleType) {
        PlatformRoleDto dto = new PlatformRoleDto();
        dto.setCode(roleType.getCode());
        dto.setName(roleType.getName());
        dto.setDescription(roleType.getDescription());
        dto.setIsBuiltin(true);
        dto.setStatus(1);
        dto.setSort(1); // 默认排序值
        dto.setEditable(false);
        return dto;
    }

    /**
     * 转换PO为DTO
     */
    private PlatformRoleDto convertToDto(PlatformRole role) {
        PlatformRoleDto dto = PlatformRoleMap.INSTANCE.toDto(role);
        dto.setEditable(!Boolean.TRUE.equals(role.getIsBuiltin()));
        return dto;
    }
}